﻿// "Therefore those skilled at the unorthodox
// are infinite as heaven and earth,
// inexhaustible as the great rivers.
// When they come to an end,
// they bagin again,
// like the days and months;
// they die and are reborn,
// like the four seasons."
// 
// - Sun Tsu,
// "The Art of War"

using System;
using log4net.Core;

namespace Infrastructure.Logging
{
    /// <summary>
    /// Used to wrap the log4net LogImpl so it have out ILog interface.
    /// all to remove dependency on log4net.
    /// </summary>
    internal class Logger : LogImpl, ILog
    {
        public Logger( ILogger logger )
                : base( logger )
        {}

        /// <summary>
        /// Log a message object with the <see cref="Level.Error"/> level including
        /// the stack trace of the <see cref="Exception"/> passed
        /// as a parameter.
        /// </summary>
        /// <param name="message">The message object to log.</param>
        /// <param name="severity">the severity of the error</param>
        /// <param name="exception">The exception to log, including its stack trace.</param>
        /// <remarks>
        /// <para>
        /// See the <see cref="ILog.Error(object)"/> form for more detailed information.
        /// </para>
        /// </remarks>
        /// <seealso cref="ILog.Error(object)"/>
        /// <seealso cref="ILog.IsErrorEnabled"/>
        public void Error( object message, Severity severity, Exception exception = null )
        {
            ThreadContext.Properties["Severity"] = (byte?)severity;
            if( exception != null )
                Error( message, exception );
            else
                Error( message );
            ThreadContext.Properties["Severity"] = null;
        }

        /// <overloads>Log a formatted message string with the <see cref="Level.Error"/> level.</overloads>
        /// <summary>
        /// Logs a formatted message string with the <see cref="Level.Error"/> level.
        /// </summary>
        /// <param name="format">A String containing zero or more format items</param>
        /// <param name="severity">the severity of the error</param>
        /// <param name="exception"></param>
        /// <param name="args">An Object array containing zero or more objects to format</param>
        /// <remarks>
        /// <para>
        /// The message is formatted using the <c>String.Format</c> method. See
        /// <see cref="String.Format(string, object[])"/> for details of the syntax of the format string and the behavior
        /// of the formatting.
        /// </para>
        /// <para>
        /// This method does not take an <see cref="Exception"/> object to include in the
        /// log event. To pass an <see cref="Exception"/> use one of the <see cref="ILog.Error(object)"/>
        /// methods instead.
        /// </para>
        /// </remarks>
        /// <seealso cref="ILog.Error(object,System.Exception)"/>
        /// <seealso cref="ILog.IsErrorEnabled"/>
        public void ErrorFormat(string format, Severity severity, Exception exception, params object[] args)
        {
            var msg = string.Format( format, args );
            Error( msg, severity, exception );
        }

        /// <overloads>Log a formatted message string with the <see cref="Level.Error"/> level.</overloads>
        /// <summary>
        /// Logs a formatted message string with the <see cref="Level.Error"/> level.
        /// </summary>
        /// <param name="format">A String containing zero or more format items</param>
        /// <param name="exception"></param>
        /// <param name="args">An Object array containing zero or more objects to format</param>
        /// <remarks>
        /// <para>
        /// The message is formatted using the <c>String.Format</c> method. See
        /// <see cref="String.Format(string, object[])"/> for details of the syntax of the format string and the behavior
        /// of the formatting.
        /// </para>
        /// <para>
        /// This method does not take an <see cref="Exception"/> object to include in the
        /// log event. To pass an <see cref="Exception"/> use one of the <see cref="ILog.Error(object)"/>
        /// methods instead.
        /// </para>
        /// </remarks>
        /// <seealso cref="ILog.Error(object,System.Exception)"/>
        /// <seealso cref="ILog.IsErrorEnabled"/>
        public void ErrorFormat(string format, Exception exception, params object[] args)
        {
            string msg = string.Format(format, args);
            Error(msg, exception);
        }

        /// <summary>
        /// Log response message log.
        /// <div>if the response is successful log the <paramref name="message"/> with successful at the end (Info level)</div>
        /// <div>if the response is failure log the <paramref name="message"/> with the failure data at the end (Error level)</div>
        /// </summary>
        /// <param name="message">the message to log the response with</param>
        /// <param name="op">the name of the operation</param>
        /// <param name="response">the response object to log</param>
        public void Response( string message, string op, BaseResponse response )
        {
            if (response.IsSuccessful)
                InfoFormat( "Successful {0} [Op: {1}]", message, op );
            else
                ErrorFormat("Failed {0}, return response... [Op: {1}] [Error: {2}] [{3}]", message, op, response.ErrorCode, response.ErrorDescription);
        }

        /// <summary>
        /// Log response message log with formatting.
        /// <div>if the response is successful log the <paramref name="messageFormat"/> with successful at the end (Info level)</div>
        /// <div>if the response is failure log the <paramref name="messageFormat"/> with the failure data at the end (Error level)</div>
        /// </summary>
        /// <param name="messageFormat">the message to log the response with</param>
        /// <param name="op">the name of the operation</param>
        /// <param name="response">the response object to log</param>
        /// <param name="args">the <paramref name="messageFormat"/> arguments list</param>
        public void ResponseFormat( string messageFormat, string op, BaseResponse response, params object[] args )
        {
            var msg = string.Format(messageFormat, args);
            if (response.IsSuccessful)
            {
                InfoFormat( "Successful {0} [Op: {1}]", msg, op );
            }
            else
            {
                ErrorFormat("Failed {0}, return response... [Op: {1}] [Error: {2}] [{3}]", msg, op, response.ErrorCode, response.ErrorDescription);
            }
        }
    }
}
